From c437a3c194e1cd6161fe8d0320a6fbf43c5e1959 Mon Sep 17 00:00:00 2001 From: Roan Kattouw Date: Wed, 26 Mar 2008 13:43:11 +0000 Subject: [PATCH] API performance enhancements (bug 13511): * Replaced $wgAPIUCUserPrefixMinLength with the more generic $wgAPIMaxDBRows * Added ApiBase::checkRowCount() which checks whether the amount of rows to be scanned is acceptable (i.e. <$wgAPIMaxDBRows). Not using this anywhere (yet?), but it's nice to have * Killed a filesort in the usercontribs query, query is now indexed nicely * Dropped the minimum length for ucuserprefix since it's no longer needed (query optimized) * Removed drnamespace from list=deletedrevs (filesorts 8M rows for drnamespace=0) * Support multiple orderings in ApiBase::addWhereRange() --- RELEASE-NOTES | 1 + includes/DefaultSettings.php | 6 +++--- includes/api/ApiQueryBase.php | 17 ++++++++++++++++- includes/api/ApiQueryDeletedrevs.php | 11 ++--------- includes/api/ApiQueryUserContributions.php | 7 +++---- 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 5418651ac4..a665820f58 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -167,6 +167,7 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN * Added inprop=talkid,subjectid to prop=info * Added help text message that specifies whether a module is POST-only * Added createonly parameter to action=edit +* Replaced $wgAPIUCUserPrefixMinLength by the more generic $wgAPIMaxDBRows === Languages updated in 1.13 === diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index b34bf3d380..132376e65d 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -2877,10 +2877,10 @@ $wgEnableWriteAPI = false; $wgAPIModules = array(); /** - * Minimum length of list=usercontribs's ucuserprefix parameter - * Setting this to a low value can open DOS windows on large wikis + * Maximum amount of rows to scan in a DB query in the API + * The default value is generally fine */ -$wgAPIUCUserPrefixMinLength = 3; +$wgAPIMaxDBRows = 5000; /** * Parser test suite files to be run by parserTests.php when no specific diff --git a/includes/api/ApiQueryBase.php b/includes/api/ApiQueryBase.php index 98a6ef39df..62ba881973 100644 --- a/includes/api/ApiQueryBase.php +++ b/includes/api/ApiQueryBase.php @@ -111,8 +111,11 @@ abstract class ApiQueryBase extends ApiBase { if (!is_null($end)) $this->addWhere($field . $before . $db->addQuotes($end)); + $order = $field . ($isDirNewer ? '' : ' DESC'); if (!isset($this->options['ORDER BY'])) - $this->addOption('ORDER BY', $field . ($isDirNewer ? '' : ' DESC')); + $this->addOption('ORDER BY', $order); + else + $this->addOption('ORDER BY', $this->options['ORDER BY'] . ', ' . $order); } protected function addOption($name, $value = null) { @@ -134,6 +137,18 @@ abstract class ApiQueryBase extends ApiBase { return $res; } + protected function checkRowCount() { + $db = $this->getDB(); + $this->profileDBIn(); + $rowcount = $db->estimateRowCount($this->tables, $this->fields, $this->where, __METHOD__, $this->options); + $this->profileDBOut(); + + global $wgAPIMaxDBRows; + if($rowcount > $wgAPIMaxDBRows) + return false; + return true; + } + public static function addTitleInfo(&$arr, $title, $prefix='') { $arr[$prefix . 'ns'] = intval($title->getNamespace()); $arr[$prefix . 'title'] = $title->getPrefixedText(); diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php index 76e6eb19bc..bdd9cc106f 100644 --- a/includes/api/ApiQueryDeletedrevs.php +++ b/includes/api/ApiQueryDeletedrevs.php @@ -111,8 +111,6 @@ class ApiQueryDeletedrevs extends ApiQueryBase { $this->addOption('LIMIT', $params['limit'] + 1); $this->addWhereRange('ar_timestamp', $params['dir'], $params['start'], $params['end']); - if(isset($params['namespace'])) - $this->addWhereFld('ar_namespace', $params['namespace']); $res = $this->select(__METHOD__); $pages = array(); $count = 0; @@ -183,10 +181,6 @@ class ApiQueryDeletedrevs extends ApiQueryBase { ), ApiBase :: PARAM_DFLT => 'older' ), - 'namespace' => array( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => 'namespace' - ), 'limit' => array( ApiBase :: PARAM_DFLT => 10, ApiBase :: PARAM_TYPE => 'limit', @@ -215,7 +209,6 @@ class ApiQueryDeletedrevs extends ApiQueryBase { 'start' => 'The timestamp to start enumerating from', 'end' => 'The timestamp to stop enumerating at', 'dir' => 'The direction in which to enumerate', - 'namespace' => 'The namespaces to search in', 'limit' => 'The maximum amount of revisions to list', 'prop' => 'Which properties to get' ); @@ -227,8 +220,8 @@ class ApiQueryDeletedrevs extends ApiQueryBase { protected function getExamples() { return array ( - 'List the first 50 deleted revisions in the Category and Category talk namespaces', - ' api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50&drnamespace=14|15', + 'List the first 50 deleted revisions', + ' api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50', 'List the last deleted revisions of Main Page and Talk:Main Page, with content:', ' api.php?action=query&list=deletedrevs&titles=Main%20Page|Talk:Main%20Page&drprop=user|comment|content' ); diff --git a/includes/api/ApiQueryUserContributions.php b/includes/api/ApiQueryUserContributions.php index 59a469f536..672c16cbf3 100644 --- a/includes/api/ApiQueryUserContributions.php +++ b/includes/api/ApiQueryUserContributions.php @@ -62,10 +62,6 @@ class ApiQueryContributions extends ApiQueryBase { if(isset($this->params['userprefix'])) { - global $wgAPIUCUserPrefixMinLength; - if(strlen($this->params['userprefix']) < $wgAPIUCUserPrefixMinLength) - $this->dieUsage("User prefixes must be at least $wgAPIUCUserPrefixMinLength characters", 'userprefix-tooshort'); - $this->prefixMode = true; $this->userprefix = $this->params['userprefix']; } @@ -145,6 +141,9 @@ class ApiQueryContributions extends ApiQueryBase { else $this->addWhereFld( 'rev_user_text', $this->usernames ); // ... and in the specified timeframe. + // Ensure the same sort order for rev_user_text and rev_timestamp + // so our query is indexed + $this->addWhereRange('rev_user_text', $this->params['dir'], null, null); $this->addWhereRange('rev_timestamp', $this->params['dir'], $this->params['start'], $this->params['end'] ); $this->addWhereFld('page_namespace', $this->params['namespace']); -- 2.20.1